001 /* 002 * Copyright 2004 Stephen J. McConnell. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 013 * implied. 014 * 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 019 package net.dpml.transit.monitor; 020 021 import java.net.URL; 022 import java.util.logging.Logger; 023 import java.util.logging.Level; 024 025 import net.dpml.lang.PID; 026 027 /** 028 * Generic adapter that redirects monitor events to a logging channel. 029 * 030 * @author <a href="http://www.dpml.net">Digital Product Meta Library</a> 031 * @version 1.0.1 032 */ 033 public class LoggingAdapter implements Adapter 034 { 035 // ------------------------------------------------------------------------ 036 // static 037 // ------------------------------------------------------------------------ 038 039 /** 040 * Constant kb value. 041 */ 042 private static final int KBYTE = 1024; 043 044 /** 045 * The logging channel. 046 */ 047 private static final String CATEGORY = ""; 048 049 private static final PID ID = new PID(); 050 051 // ------------------------------------------------------------------------ 052 // state 053 // ------------------------------------------------------------------------ 054 055 private Logger m_logger; 056 057 // ------------------------------------------------------------------------ 058 // constructor 059 // ------------------------------------------------------------------------ 060 061 /** 062 * Creation of a new console adapter that is used to redirect transit events 063 * the system output stream. 064 */ 065 public LoggingAdapter() 066 { 067 this( Logger.getLogger( CATEGORY ) ); 068 } 069 070 /** 071 * Creation of a new console adapter that is used to redirect transit events 072 * the system output stream. 073 * @param logger the assigned logging channel 074 */ 075 public LoggingAdapter( Logger logger ) 076 { 077 m_logger = logger; 078 } 079 080 /** 081 * Creation of a new console adapter that is used to redirect transit events 082 * the system output stream. 083 * @param category the logging channel category name 084 */ 085 public LoggingAdapter( String category ) 086 { 087 m_logger = Logger.getLogger( category ); 088 } 089 090 // ------------------------------------------------------------------------ 091 // Adapter 092 // ------------------------------------------------------------------------ 093 094 /** 095 * Return TRUE is trace level logging is enabled. 096 * @return the enabled state of trace logging 097 */ 098 public boolean isTraceEnabled() 099 { 100 return m_logger.isLoggable( Level.FINER ); 101 } 102 103 /** 104 * Return TRUE is debug level logging is enabled. 105 * @return the enabled state of debug logging 106 */ 107 public boolean isDebugEnabled() 108 { 109 return m_logger.isLoggable( Level.FINE ); 110 } 111 112 /** 113 * Return TRUE is info level logging is enabled. 114 * @return the enabled state of info logging 115 */ 116 public boolean isInfoEnabled() 117 { 118 return m_logger.isLoggable( Level.INFO ); 119 } 120 121 /** 122 * Return TRUE is error level logging is enabled. 123 * @return the enabled state of error logging 124 */ 125 public boolean isWarnEnabled() 126 { 127 return m_logger.isLoggable( Level.WARNING ); 128 } 129 130 /** 131 * Return TRUE is error level logging is enabled. 132 * @return the enabled state of error logging 133 */ 134 public boolean isErrorEnabled() 135 { 136 return m_logger.isLoggable( Level.SEVERE ); 137 } 138 139 /** 140 * Log a debug message is trace mode is enabled. 141 * @param message the message to log 142 */ 143 public void trace( String message ) 144 { 145 if( isTraceEnabled() ) 146 { 147 m_logger.finer( message ); 148 } 149 } 150 151 /** 152 * Log a debug message is debug mode is enabled. 153 * @param message the message to log 154 */ 155 public void debug( String message ) 156 { 157 if( isDebugEnabled() ) 158 { 159 m_logger.fine( message ); 160 } 161 } 162 163 /** 164 * Log a info level message. 165 * @param message the message to log 166 */ 167 public void info( String message ) 168 { 169 if( isInfoEnabled() ) 170 { 171 m_logger.info( message ); 172 } 173 } 174 175 /** 176 * Record a warning message. 177 * @param message the warning message to record 178 */ 179 public void warn( String message ) 180 { 181 if( isWarnEnabled() ) 182 { 183 m_logger.warning( message ); 184 } 185 } 186 187 /** 188 * Record a warning message. 189 * @param message the warning message to record 190 * @param cause the causal exception 191 */ 192 public void warn( String message, Throwable cause ) 193 { 194 if( isWarnEnabled() ) 195 { 196 m_logger.log( Level.WARNING, message, cause ); 197 } 198 } 199 200 /** 201 * Log a error message. 202 * @param message the message to log 203 */ 204 public void error( String message ) 205 { 206 if( isErrorEnabled() ) 207 { 208 m_logger.log( Level.SEVERE, message ); 209 } 210 } 211 212 /** 213 * Log a error message. 214 * @param message the message to log 215 * @param e the causal exception 216 */ 217 public void error( String message, Throwable e ) 218 { 219 if( isErrorEnabled() ) 220 { 221 m_logger.log( Level.SEVERE, message, e ); 222 } 223 } 224 225 /** 226 * Return a child logger. 227 * @param category the sub-category name. 228 * @return the child logging channel 229 */ 230 public net.dpml.util.Logger getChildLogger( String category ) 231 { 232 if( ( null == category ) || "".equals( category ) ) 233 { 234 return this; 235 } 236 else 237 { 238 String name = m_logger.getName(); 239 String path = trim( name + "." + category ); 240 return new LoggingAdapter( Logger.getLogger( path ) ); 241 } 242 } 243 244 private String trim( String path ) 245 { 246 if( path.startsWith( "." ) ) 247 { 248 return trim( path.substring( 1 ) ); 249 } 250 else if( ".".equals( path ) ) 251 { 252 return ""; 253 } 254 else 255 { 256 return path; 257 } 258 } 259 260 /** 261 * Handle download notification. 262 * @param resource the resource under attention 263 * @param total the estimated download size 264 * @param count the progress towards expected 265 */ 266 public void notify( URL resource, int total, int count ) 267 { 268 String path = resource.toString(); 269 if( path.startsWith( "file:" ) ) 270 { 271 return; 272 } 273 if( isAnt() || ( "true".equals( System.getProperty( "dpml.subprocess" ) ) ) ) 274 { 275 if( count == 0 ) 276 { 277 info( "downloading [" + resource + "] (" + getFranctionalValue( total ) + ")" ); 278 } 279 return; 280 } 281 282 if( isInfoEnabled() ) 283 { 284 String max = getFranctionalValue( total ); 285 String value = getFranctionalValue( count ); 286 int pad = max.length() - value.length(); 287 String level = getLogHeader(); 288 String process = getProcessHeader(); 289 StringBuffer buffer = new StringBuffer( process + level ); 290 String name = path.substring( path.lastIndexOf( '/' ) + 1 ); 291 buffer.append( "(" + m_logger.getName() + "): " ); 292 buffer.append( "retrieving: " + name + " " ); 293 for( int i=0; i < pad; i++ ) 294 { 295 buffer.append( " " ); 296 } 297 buffer.append( value ); 298 buffer.append( "k/" ); 299 if( total == 0 ) 300 { 301 buffer.append( "?" ); 302 } 303 else 304 { 305 buffer.append( max ); 306 buffer.append( "k\r" ); 307 } 308 if( total == count ) 309 { 310 System.out.println( buffer.toString() ); 311 } 312 else 313 { 314 System.out.print( buffer.toString() ); 315 } 316 } 317 } 318 319 /** 320 * Internal utility to return the locaized logging level name. 321 * @return the localized name 322 */ 323 private String getLogHeader() 324 { 325 StringBuffer buffer = new StringBuffer(); 326 buffer.append( "[" ); 327 Level level = getLoggerLevel( m_logger ); 328 buffer.append( level.getLocalizedName() ); 329 buffer.append( " " ); 330 String tag = buffer.toString(); 331 return tag.substring( 0, EIGHT ) + "] "; 332 } 333 334 private String getProcessHeader() 335 { 336 StringBuffer buffer = new StringBuffer(); 337 buffer.append( "[" ); 338 buffer.append( ID.getValue() ); 339 buffer.append( " " ); 340 String tag = buffer.toString(); 341 return tag.substring( 0, PROCESS_HEADER_WIDTH ) + "] "; 342 } 343 344 345 private Level getLoggerLevel( Logger logger ) 346 { 347 Level level = logger.getLevel(); 348 if( level != null ) 349 { 350 return level; 351 } 352 else 353 { 354 Logger parent = logger.getParent(); 355 if( null != parent ) 356 { 357 return getLoggerLevel( parent ); 358 } 359 else 360 { 361 final String error = 362 "Logging level is not defined."; 363 throw new IllegalStateException( error ); 364 } 365 } 366 } 367 368 // ------------------------------------------------------------------------ 369 // implementation 370 // ------------------------------------------------------------------------ 371 372 /** 373 * Test is the runtime environment is ant. 374 * @return true if ant is visible 375 */ 376 private boolean isAnt() 377 { 378 return null != System.getProperty( "ant.home" ); 379 /* 380 try 381 { 382 ClassLoader.getSystemClassLoader().loadClass( "org.apache.tools.ant.launch.AntMain" ); 383 return true; 384 } 385 catch( Exception e ) 386 { 387 return false; 388 } 389 */ 390 } 391 392 /** 393 * Return a string representing the number of kilobytes relative to the supplied 394 * total bytes. 395 * @param total the byte value 396 * @return the string to log 397 */ 398 private static String getFranctionalValue( int total ) 399 { 400 final int offset = 3; 401 402 float realTotal = new Float( total ).floatValue(); 403 float realK = new Float( KBYTE ).floatValue(); 404 float r = ( realTotal / realK ); 405 406 String value = new Float( r ).toString(); 407 int j = value.indexOf( "." ); 408 if( j > -1 ) 409 { 410 int q = value.length(); 411 int k = q - j; 412 if( k > offset ) 413 { 414 return value.substring( 0, j + offset ); 415 } 416 else 417 { 418 return value; 419 } 420 } 421 else 422 { 423 return value; 424 } 425 } 426 427 /** 428 * Internal utility to log a message to system.out. 429 * @param message the message to log 430 */ 431 private void log( String message ) 432 { 433 m_logger.fine( message ); 434 } 435 436 private static final int EIGHT = 8; 437 private static final int PROCESS_HEADER_WIDTH = 6; 438 } 439